//给你一个字符串 s ，找出其中最长的回文子序列，并返回该序列的长度。 
//
// 子序列定义为：不改变剩余字符顺序的情况下，删除某些字符或者不删除任何字符形成的一个序列。 
//
// 
//
// 示例 1： 
//
// 
//输入：s = "bbbab"
//输出：4
//解释：一个可能的最长回文子序列为 "bbbb" 。
// 
//
// 示例 2： 
//
// 
//输入：s = "cbbd"
//输出：2
//解释：一个可能的最长回文子序列为 "bb" 。
// 
//
// 
//
// 提示： 
//
// 
// 1 <= s.length <= 1000 
// s 仅由小写英文字母组成 
// 
// Related Topics 字符串 动态规划 👍 707 👎 0

package com.cute.leetcode.editor.cn;
public class LongestPalindromicSubsequence {
    public static void main(String[] args) {
        Solution solution = new LongestPalindromicSubsequence().new Solution();
    }
    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        /**
         * 本质就是求s和s逆序的最长公共子序列
         * 使用dp求解
         * dp[i][j]为取i-j的子串能达到的最大回文串长度
         * 如果s[i] == s[j] 那么直接是dp[i+1][j-1]+2
         * 如果不相等的时候，那么就是两个方向的最大值，即为max(dp[i+1][j], dp[i][j-1])
         * 所以遍历顺序是从下到上，从左到右，最终结果在右上角
         */
        public int longestPalindromeSubseq(String s) {
            char[] chars = s.toCharArray();
            int len = chars.length;
            int[][] dp = new int[len][len];
            for (int i = 0; i < len; i++) dp[i][i] = 1;
            for (int i = len-1; i >= 0 ; i--) {
                for (int j = i+1; j < len ; j++) {
                    if (chars[i] == chars[j]) dp[i][j] = dp[i+1][j-1] + 2;
                    else dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]);
                }
            }
            return dp[0][len-1];
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}